package com.smile.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.smile.api.OssApi;
import com.smile.commons.file.FileUtils;
import com.smile.commons.gps.RouteFileUtils;
import com.smile.commons.gps.domain.*;
import com.smile.commons.gps.domain.kml.*;
import com.smile.commons.gps.kml.*;
import com.smile.commons.page.R;
import com.smile.model.dto.request.GenerateAirlineFileRequestDTO;
import com.smile.model.dto.request.GenerateWaypointActionRequestDTO;
import com.smile.model.dto.request.GenerateWaypointRequestDTO;
import com.smile.model.response.PutFileResponse;
import com.smile.model.response.response.GenerateAirlineFileResponseDTO;
import com.smile.service.FlightTaskService;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.smile.commons.gps.RouteFileUtils.buildKml;
import static com.smile.commons.gps.RouteFileUtils.buildWpml;

@Service
public class FlightTaskServiceImpl implements FlightTaskService {

    private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";

    private static final String LOCAL_KMZ_FILE_PATH = "file" + File.separator + "kmz" + File.separator;

    @Autowired
    private OssApi ossApi;

    @Override
    public GenerateAirlineFileResponseDTO generateAirlineFile(GenerateAirlineFileRequestDTO generateAirlineFileRequestDTO) throws IOException {
        KmlParams uavRouteReq = new KmlParams();
        if (generateAirlineFileRequestDTO.getAirlineType() == 0) {
            uavRouteReq.setTemplateType("waypoint");
        }
        //这里先写死 主类型是大疆机场3
        uavRouteReq.setDroneType(DroneEnumValueEnums.DJ_AIRPORT.getValue());
        //子类型M4td
        uavRouteReq.setSubDroneType(DroneEnumValueEnums.M4D_M4TD.getValue());
        uavRouteReq.setPayloadType(PayloadTypeEnums.M4TD.getValue());

        uavRouteReq.setPayloadPosition(PayloadPositionIndexEnums.ZERO.getValue());


        uavRouteReq.setImageFormat("zoom");

        switch (generateAirlineFileRequestDTO.getFinishAction()) {
            case 0:
                //自动返航
                uavRouteReq.setFinishAction(FinishActionEnums.GO_HOME.getValue());
            case 1:
                //返回航线到起始点悬停
                uavRouteReq.setFinishAction(FinishActionEnums.GOTO_FIRST_WAYPOINT.getValue());
            case 2:
                //退出航线模式
                uavRouteReq.setFinishAction(FinishActionEnums.NO_ACTION.getValue());
            case 3:
                //原地降落
                uavRouteReq.setFinishAction(FinishActionEnums.AUTO_LAND.getValue());
        }

        uavRouteReq.setExitOnRcLostAction(ExitOnRCLostEnums.GO_CONTINUE.getValue());
        uavRouteReq.setGlobalHeight(generateAirlineFileRequestDTO.getGlobalHeight());
        uavRouteReq.setAutoFlightSpeed(generateAirlineFileRequestDTO.getAutoFlightSpeed());


        //TODO 兴趣点 暂时省略


        WaypointTurnReq waypointTurnReq = new WaypointTurnReq();
        waypointTurnReq.setWaypointTurnMode("toPointAndStopWithContinuityCurvature");
        waypointTurnReq.setUseStraightLine(1);
        waypointTurnReq.setWaypointTurnDampingDist(1D);
        uavRouteReq.setWaypointTurnReq(waypointTurnReq);
        uavRouteReq.setGimbalPitchMode(GimbalPitchModeEnums.USE_POINT_SETTING.getValue());
        uavRouteReq.setTakeOffRefPoint(generateAirlineFileRequestDTO.getTakeOffRefPoint());


        uavRouteReq.setRoutePointList(generateWayPoint(generateAirlineFileRequestDTO.getWayPoints()));


        uavRouteReq.setWaypointTurnReq(waypointTurnReq);
        uavRouteReq.setGimbalPitchMode(GimbalPitchModeEnums.USE_POINT_SETTING.getValue());
        uavRouteReq.setTakeOffRefPoint(generateAirlineFileRequestDTO.getTakeOffRefPoint());
        uavRouteReq.setWaypointHeadingReq(new WaypointHeadingReq());

        MappingTypeReq mappingTypeReq = new MappingTypeReq();
        mappingTypeReq.setCollectionMethod(CollectionMethodEnums.ORTHO.getValue());
        mappingTypeReq.setLensType(LensTypeEnums.CAMERA.getValue());
        mappingTypeReq.setOverlapH(50);
        mappingTypeReq.setOverlapW(50);
        mappingTypeReq.setElevationOptimizeEnable(0);
        mappingTypeReq.setShootType(ShootTypeEnums.TIME.getValue());
        mappingTypeReq.setDirection("50");
        mappingTypeReq.setMargin("50");


        mappingTypeReq.setCoordinates(new ArrayList<>());

        uavRouteReq.setMappingTypeReq(mappingTypeReq);

        PointActionReq pointActionReq = new PointActionReq();
        pointActionReq.setActionIndex(1);
        pointActionReq.setHoverTime(5.00d);
        pointActionReq.setAircraftHeading(50d);
        pointActionReq.setTakePhotoType(1);
        pointActionReq.setUseGlobalImageFormat(1);
        pointActionReq.setImageFormat(ImageFormatEnums.ZOOM.getValue());
        pointActionReq.setGimbalPitchRotateAngle(50d);
        pointActionReq.setGimbalYawRotateAngle(50d);
        pointActionReq.setZoom(200d);
        pointActionReq.setStartRecord(Boolean.TRUE);
        pointActionReq.setStopRecord(Boolean.FALSE);
        List<PointActionReq> pointActionReqList = new ArrayList<>();
        pointActionReqList.add(pointActionReq);

        uavRouteReq.setStartActionList(pointActionReqList);

        RouteFileUtils.KmlParamsExtension kmlParamsExtension = new RouteFileUtils.KmlParamsExtension();
        kmlParamsExtension.setTakeOffSecurityHeight(generateAirlineFileRequestDTO.getTakeOffSecurityHeight());
        kmlParamsExtension.setGlobalRTHHeight(generateAirlineFileRequestDTO.getGlobalRTHHeight());
        kmlParamsExtension.setGlobalTransitionalSpeed(generateAirlineFileRequestDTO.getGlobalTransitionalSpeed());

        String fileName = UUID.randomUUID().toString().replaceAll("-", "");

        String s = RouteFileUtils.buildKmz(kmlParamsExtension, fileName, uavRouteReq);
        File file = new File(s);

        MultipartFile multipartFile = FileUtils.fileToMultipartFile(file, s);
        R<PutFileResponse> putFileResponseR = ossApi.putkmlFile(s, multipartFile);
        if (ObjectUtil.isNotNull(putFileResponseR) && ObjectUtil.isNotNull(putFileResponseR.getData())) {
//            String s1 = putFileResponseR.getData().getUrl().replaceAll("\\\\", "/");
            System.out.println("url=" + putFileResponseR.getData().getUrl());
            GenerateAirlineFileResponseDTO generateAirlineFileResponseDTO = new GenerateAirlineFileResponseDTO();
            generateAirlineFileResponseDTO.setUrl(putFileResponseR.getData().getUrl());
            generateAirlineFileResponseDTO.setETag(putFileResponseR.getData().getETag());
            return generateAirlineFileResponseDTO;
        } else {
            throw new RuntimeException("航线文件保存失败");
        }
    }


    public List<RoutePointInfo> generateWayPoint(List<GenerateWaypointRequestDTO> wayPoints) {
        List<RoutePointInfo> collect = wayPoints.stream().map(wayPoint -> {

            RoutePointInfo routePointReq = new RoutePointInfo();

            //TODO
            routePointReq.setRoutePointIndex(wayPoint.getIndex());


            routePointReq.setLongitude(wayPoint.getLongitude().doubleValue());
            routePointReq.setLatitude(wayPoint.getLatitude().doubleValue());
            routePointReq.setHeight(wayPoint.getHeight());
            routePointReq.setSpeed(wayPoint.getWaypointSpeed().doubleValue());

//            routePointReq.setWaypointTurnReq(waypointTurnReq);
//            routePointReq.setGimbalPitchAngle(50D);

            WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq();

            switch (wayPoint.getAttitudeHead()) {
                case 0:
                    //沿航线方向
                    waypointHeadingReq.setWaypointHeadingMode(WaypointHeadingModeEnums.FOLLOW_WAYLINE.getValue());
                case 1:
                    //手动控制
                    waypointHeadingReq.setWaypointHeadingMode(WaypointHeadingModeEnums.MANUALLY.getValue());
                case 2:
                    //锁定当前偏航角
                    waypointHeadingReq.setWaypointHeadingMode(WaypointHeadingModeEnums.FIXED.getValue());
            }

            Map<Integer, Integer> map = new HashMap<>();
            wayPoint.getActions().forEach(i -> {
                map.put(i.getActionType(), i.getActionValue());
            });

            if (map.containsKey(8)) {
                routePointReq.setDistanceInterval(map.get(8).doubleValue());
            } else {
                routePointReq.setDistanceInterval(0.0);
            }

            if (map.containsKey(9)) {
                routePointReq.setTimeInterval(map.get(9).doubleValue());
            } else {
                routePointReq.setTimeInterval(0.0);
            }

            if (map.containsKey(10)) {
                routePointReq.setEndIntervalRouteIndex(1);
            }

            routePointReq.setWaypointHeadingReq(waypointHeadingReq);
            routePointReq.setActions(createPointAction(wayPoint.getActionIndex(), wayPoint.getActions(), wayPoint.getImageFormat()));

            return routePointReq;
        }).collect(Collectors.toList());


        return collect;
    }

    public List<PointActionReq> createPointAction(Integer actionIndex, List<GenerateWaypointActionRequestDTO> actions, Integer imageFormat) {
//        PointActionReq pointActionReq = new PointActionReq();
//        pointActionReq.setActionIndex(actionIndex);

        List<PointActionReq> collect = actions.stream().map(action -> {
            PointActionReq pointActionReq = new PointActionReq();
            pointActionReq.setActionIndex(actionIndex);

            if (action.getActionType() == 0) {
                pointActionReq.setImageFormat(ImageFormatEnums.WIDE.getValue());
            }

            if (action.getActionType() == 1) {
                pointActionReq.setHoverTime(action.getActionValue().doubleValue());
            }

            if (action.getActionType() == 2) {
                pointActionReq.setAircraftHeading(action.getActionValue().doubleValue());
            }

            if (action.getActionType() == 3) {
                pointActionReq.setUseGlobalImageFormat(1);
            }

            if (action.getActionType() == 4) {
                pointActionReq.setTakePhotoType(1);
            }

            if (action.getActionType() == 5) {
                pointActionReq.setStartRecord(Boolean.TRUE);
            }

            if (action.getActionType() == 6) {
                pointActionReq.setZoom(action.getActionValue().doubleValue());
            }

            if (action.getActionType() == 7) {
                pointActionReq.setStartRecord(Boolean.TRUE);
            }

            return pointActionReq;
        }).collect(Collectors.toList());


        return collect;
    }

    public RoutePointInfo createRoutePointReq(Integer index, WaypointHeadingReq waypointHeadingReq, WaypointTurnReq waypointTurnReq, Double longitude, Double latitude, BigDecimal height) {
        RoutePointInfo routePointReq = new RoutePointInfo();
        routePointReq.setRoutePointIndex(index);
        routePointReq.setLongitude(longitude);
        routePointReq.setLatitude(latitude);
        routePointReq.setHeight(height);
        routePointReq.setSpeed(20d);
        routePointReq.setWaypointHeadingReq(waypointHeadingReq);
        routePointReq.setWaypointTurnReq(waypointTurnReq);
        routePointReq.setGimbalPitchAngle(50D);


        PointActionReq pointActionReq = new PointActionReq();
        pointActionReq.setActionIndex(1);
        pointActionReq.setHoverTime(5.00d);
        pointActionReq.setAircraftHeading(108.14303588867188);
        pointActionReq.setTakePhotoType(1);
        pointActionReq.setUseGlobalImageFormat(1);
        pointActionReq.setImageFormat(ImageFormatEnums.ZOOM.getValue());
        pointActionReq.setGimbalPitchRotateAngle(50d);
        pointActionReq.setGimbalYawRotateAngle(50d);
        pointActionReq.setZoom(200d);
        pointActionReq.setStartRecord(Boolean.TRUE);
        pointActionReq.setStopRecord(Boolean.FALSE);
        List<PointActionReq> pointActionReqList = new ArrayList<>();
        pointActionReqList.add(pointActionReq);
        routePointReq.setActions(pointActionReqList);
        routePointReq.setTimeInterval(5d);
        routePointReq.setDistanceInterval(5d);
        routePointReq.setEndIntervalRouteIndex(3);
        return routePointReq;
    }

    private static void buildKmlParams(KmlParams kmlParams, KmlInfo kmlInfo) {
        KmlFolder folder = kmlInfo.getDocument().getFolder();
        kmlParams.setGlobalHeight(new BigDecimal(kmlInfo.getDocument().getKmlMissionConfig().getGlobalRTHHeight()));
        kmlParams.setAutoFlightSpeed(new BigDecimal(folder.getAutoFlightSpeed()));

        WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq();
        waypointHeadingReq.setWaypointHeadingMode(folder.getGlobalWaypointHeadingParam().getWaypointHeadingMode());
        waypointHeadingReq.setWaypointHeadingAngle(StringUtils.isNotBlank(folder.getGlobalWaypointHeadingParam().getWaypointHeadingAngle()) ?
                new BigDecimal(folder.getGlobalWaypointHeadingParam().getWaypointHeadingAngle()) : null);
        waypointHeadingReq.setWaypointPoiPoint(StringUtils.isNotBlank(folder.getGlobalWaypointHeadingParam().getWaypointPoiPoint()) ? folder.getGlobalWaypointHeadingParam().getWaypointPoiPoint() : null);
        kmlParams.setWaypointHeadingReq(waypointHeadingReq);

        WaypointTurnReq waypointTurnReq = new WaypointTurnReq();
        waypointTurnReq.setWaypointTurnMode(folder.getGlobalWaypointTurnMode());
        waypointTurnReq.setUseStraightLine(StringUtils.isNotBlank(folder.getGlobalUseStraightLine()) ? Integer.valueOf(folder.getGlobalUseStraightLine()) : null);

        kmlParams.setWaypointTurnReq(waypointTurnReq);
        kmlParams.setGimbalPitchMode(folder.getGimbalPitchMode());
        kmlParams.setPayloadPosition(Integer.valueOf(kmlInfo.getDocument().getKmlMissionConfig().getPayloadInfo().getPayloadPositionIndex()));
        kmlParams.setImageFormat(folder.getPayloadParam().getImageFormat());
    }

    private void handleRouteUpdate(KmlInfo kmlInfo, UavRouteReq uavRouteReq, String fileType, KmlParams kmlParams) {
        if (StringUtils.isNotBlank(uavRouteReq.getFinishAction())) {
            kmlInfo.getDocument().getKmlMissionConfig().setFinishAction(uavRouteReq.getFinishAction());
        }
        if (StringUtils.isNotBlank(uavRouteReq.getExitOnRcLostAction())) {
            kmlInfo.getDocument().getKmlMissionConfig().setExitOnRCLost(ExitOnRCLostEnums.EXECUTE_LOST_ACTION.getValue());
            kmlInfo.getDocument().getKmlMissionConfig().setExecuteRCLostAction(uavRouteReq.getExitOnRcLostAction());
        }
        if (CollectionUtil.isNotEmpty(uavRouteReq.getRoutePointList())) {
            List<KmlPlacemark> placemarkList = new ArrayList<>();
            for (RoutePointReq routePointReq : uavRouteReq.getRoutePointList()) {
                RoutePointInfo routePointInfo = BeanUtil.copyProperties(routePointReq, RoutePointInfo.class);
                KmlPlacemark kmlPlacemark = RouteFileUtils.buildKmlPlacemark(routePointInfo, kmlParams, fileType);
                placemarkList.add(kmlPlacemark);
            }
            kmlInfo.getDocument().getFolder().setPlacemarkList(placemarkList);
        }
    }

}
